#include "updatefile.h"

#include <QDir>
#include <iostream>
#include <qtextcodec.h>
#include <qfile.h>
#include <qstring.h>



//bool copyDir(const QString& fromDirPath, const QString& toDirPath, bool bCoverIfFileExists);
//void deleteDirectory(QFileInfo fileList);
//void clearDirectory(const QString dirName);
//QStringList findCEPro(const QString& usbPath);

UpdateFile::UpdateFile(QObject *parent) :
    QObject(parent)
{
//    updateResource = NULL;
    m_isUpdate = false;

    //usb监控线程
    usbMonitor = new UsbMonitor(this);
    connect(usbMonitor, SIGNAL(usbChange(int,QString)), this, SLOT(findUsbDisk(int,QString)));
    connect(usbMonitor, SIGNAL(finished()), usbMonitor, SLOT(deleteLater()));
    usbMonitor->start();

    xmlParser = new XmlParser(this);
    connect(xmlParser, SIGNAL(parserFinish(int,QString,QString,QString,QString)), this, SLOT(receXmlParser(int,QString,QString,QString,QString)));

    currentVersion = configClass.getScheduleVersion();
    backUpPath = g_installPath + "/" + BACKUPRESOURCEPATH;

    m_usbTimer = new QTimer(this);
    m_usbTimer->setSingleShot(true);
    connect(m_usbTimer, SIGNAL(timeout()), this, SLOT(umountUsb()));

    m_umountCount = 0;
}

UpdateFile::~UpdateFile()
{
    usbMonitor->stop();
//    usbMonitor->wait(200);
    usbMonitor->exit();
}

bool UpdateFile::checkfile(const QString& strPath)
{
    QString strFilePath = strPath + "/PIDS";
    QDir dir(strPath);
    if (!dir.exists())
    {
        return false;
    }

    strFilePath += "/";

    return true;
}

bool UpdateFile::start()
{
    return true;
}

void UpdateFile::stop()
{

}

//处理了20％，则返回值为20
int UpdateFile::percent()
{
    int percent = 0;
    return percent;
}

//备份当前的资源文件
bool UpdateFile::backUpData() const
{
    QDir dir(backUpPath);
    if (!dir.exists())
    {
        dir.mkdir(backUpPath);
    }

//    qDebug() << "backUpPath======================>>" << backUpPath;
    //从pro文件中读出当前的资源文件名和数据库名
    QString appPath = g_installPath;
    QString proName = configClass.getScheduleProName() + ".CEPrj";
    QString curProAbPath = appPath+ "/" + proName;
    QString curResourceName;
    QString curDBName;
    QString curPublishTime;
    if (xmlParser->parserFile(curProAbPath, curPublishTime, curDBName, curResourceName) < 0)
    {
        return false;
    }
    QString curDBPath = appPath + "/" + curDBName;
    QString curRePath = appPath + "/" + curResourceName;

    //将相应的APP路径换成备份路径，然后将相应的pro，数据库文件和资源文件拷贝过去
    QString backUpDBPath = backUpPath + "/" + curDBName;
    QString backUpResourcePath = backUpPath + "/" + curResourceName;
    QString backUpProPath = backUpPath + "/" + proName;

    clearDirectory(backUpPath);

    QFile file(backUpProPath);
    if (file.exists())
    {
        file.remove(backUpProPath);
    }
    file.copy(curProAbPath, backUpProPath);
//    file.copy(curDBPath, backUpDBPath);


    QFile file1(backUpDBPath);
    if (file1.exists())
    {
        file1.remove(backUpDBPath);
    }
    file1.copy(curDBPath, backUpDBPath);

    return copyDir(curRePath, backUpResourcePath, true);
}

//还原备份的文件
bool UpdateFile::getBackUpData()
{

    QFile file;
    ProjectStruct pro;

//    qDebug() << "getBackUpData ===========================================+ getBackUpData";
    QDir dir(backUpPath);
    if (!dir.exists())
    {
        emit updateFinish(-7, pro);
        return false;
    }

    //接着在备份文件中找出备份的pro文件，然后读出备份的数据名和资源名字，得到备份的文件的相关路径
    QStringList prolist = findCEPro(backUpPath);
    QString resourceName;
    QString dbName;
    QString publishTime;

    if (prolist.count() == 1)
    {
        int returnErr = xmlParser->parserFile(prolist.at(0), publishTime, dbName, resourceName);
        if (returnErr < 0)
            return false;
    }
    QString backUpDBPath = backUpPath + "/" + dbName;
    QString backUpResourcePath = backUpPath + "/" + resourceName;

    if (!file.exists(backUpDBPath) || !dir.exists(backUpResourcePath))
    {
        return false;
    }


    //从pro文件中读出当前的资源文件名和数据库名
    QString appPath = g_installPath;
    QString proName = configClass.getScheduleProName() + ".CEPrj";
    QString curProAbPath = appPath+ "/" + proName;
    QString curResourceName;
    QString curDBName;
    QString curPublishTime;

    if (xmlParser->parserFile(curProAbPath, curPublishTime, curDBName, curResourceName) >= 0)
    {
        //首先将当前的资源先清空，然后再进行备份还原
        QString curDBPath = appPath + "/" +  curDBName;
        QString curResourcePath = appPath + "/" + curResourceName;

        if (file.exists(curDBPath))
        {
            file.remove(curDBPath);
        }

        dir = QDir(curResourcePath);
        if (dir.exists())
        {
            clearDirectory(curResourcePath);
            dir.rmdir(curResourcePath);
        }
    }
    //接着得到要还原的路径，一般就在APP当前路径下加上相应的资源文件路径
    QFileInfo info(prolist.at(0));
    QString returnProPath = appPath + "/" + info.fileName();
    QString returnDBPath = appPath + "/" + dbName;
    QString returnRePath = appPath + "/" + resourceName;

    //备份数据开始还原
    QFile file1(returnProPath);
    if (file1.exists())
    {
        file1.remove(returnProPath);
    }
    file1.copy(prolist.at(0), returnProPath);
    if (file1.exists(returnDBPath))
    {
        file1.remove(returnDBPath);
    }
    file1.copy(backUpDBPath, returnDBPath);


    copyDir(backUpResourcePath, returnRePath, true);

    currentVersion = publishTime;
    configClass.setScheduleVersion(currentVersion);
    configClass.setScheduleProName(info.baseName());

     return true;
}


//找到u盘槽函数，如果找到Ｕ盘就会触发些函数
//开启一个线程来更新检测Ｕ盘并更新资源
void UpdateFile::findUsbDisk(const int driver, const QString &usbPath)
{
//    qDebug() << "============ findUsbDisk ================>" << m_isUpdate << driver << usbPath;

    ProjectStruct project;
    if (m_isUpdate)
        return;

    m_isUpdate = true;

    if (driver == -1)
    {
        emit updateFinish(-5, project);
        m_isUpdate = false;
        return;
    } else {
        startToUpdate(0, "-1");
    }

    UsbThread *usbThread = new UsbThread(this);
    connect(usbThread, SIGNAL(startToUpdate(int,QString)), this, SIGNAL(startToUpdate(int,QString)));
    connect(usbThread, SIGNAL(updateFinish(int,ProjectStruct)), this, SIGNAL(updateFinish(int,ProjectStruct)));
    connect(usbThread, SIGNAL(umountUsbState(int)), this, SIGNAL(umountUsbState(int)));
    connect(usbThread, SIGNAL(finished()), this, SLOT(updateFinish()));
    connect(usbThread, SIGNAL(finished()), usbThread, SLOT(deleteLater()));


    usbThread->setUpdatePath(usbPath, RESOURCEPATHBACKUP);

    usbThread->start();

    return;

    QString path = usbPath;

    //linux自动挂载U盘时，如果出现空格将会转换成"\040",所以要先将他转换成空格，得到正确的路径
    if (path.contains("\\040"))
    {
        path.replace("\\040", " ");
    }
    m_usbPathList.append(path);

    QDir dir(path);
    if (dir.exists())
    {
        updateXmlPath = path + "/";
        QStringList xmlList = findCEPro(path);
        emit startToUpdate(xmlList.count(), "-1");
        if (xmlList.isEmpty())
        {
            emit updateFinish(-1, project);
        } else {
            for(int i = 0; i < xmlList.count(); i++)
            {
                xmlParser->setParsetFile(xmlList.at(i));
            }
        }
    }
}


void UpdateFile::updateFinish()
{
//    qDebug() << "UpdateFile finish=======================<<<<";
    m_isUpdate = false;
}

//收到XML解析完成传过来的信息,先检测要更新的文件是否完整,如果完整则备份原来的数据,接着删除原先的数据,然后进行更新(即拷贝)
void UpdateFile::receXmlParser(int err, const QString &proPath, const QString &publishTime, const QString &dbName, const QString &resourcePath)
{
    ProjectStruct project;

    QString appPath = g_installPath;

    if (err < 0)
    {
        emit updateFinish(-1, project);
    } else {
        if (currentVersion.toLongLong() > publishTime.toLongLong())
        {
            emit updateFinish(-2, project);
        } else {
            QDir dir;
            QFile file;
            //从USB中的pro文件中读出的数据得到USB中可以更新的数据路径
            QFileInfo info(proPath);
            QString usbDBPath = info.absolutePath() + "/" + dbName;
            QString usbResourcePath = info.absolutePath() + "/" + resourcePath;
            QString usbProPath = proPath;

            //检查USB中的文件是否齐全
            if (!file.exists(usbDBPath) || !dir.exists(usbResourcePath))
            {
                emit updateFinish(-6, project);
            } else {

                //从pro文件中读出当前的资源文件名和数据库名
                QString appPath = g_installPath;
                QString proName = configClass.getScheduleProName() + ".CEPrj";
                QString curProPath = appPath+ "/" + proName;
                QString curResourceName;
                QString curDBName;
                QString curPublishTime;

                //解析当前pro文件,如果正常,那么开始备份,否则不进行备份操作
                if (xmlParser->parserFile(curProPath, curPublishTime, curDBName, curResourceName) >= 0)
                {
                    QString curDBPath = appPath + "/" + curDBName;
                    QString curRePath = appPath + "/" + curResourceName;

                    if (file.exists(curDBPath) && dir.exists(curRePath))
                    {
                        //先将备份文件清除，然后开始备份，再进行更新
                        clearDirectory(backUpPath);
                        //备份当前版本
                        backUpData();
                    }
                    if (file.exists(curProPath))
                    {
                        file.remove(curProPath);
                    }

                    if (file.exists(curDBPath))
                    {
                        file.remove(curDBPath);
                    }

                    if(dir.exists(curRePath))
                    {
                        clearDirectory(curRePath);
                    }
                }

                //得到要更新的路径
                QString updateDBPath = appPath + "/" + dbName;
                QString updateResourcePath = appPath + "/" + resourcePath;
                QString updateProPath = appPath + "/" + info.fileName();

                //首先要检查是否要更新的文件在原本的数据是否存在，把他们删除
                if (file.exists(updateDBPath))
                {
                    file.remove(updateDBPath);
                }
                if (file.exists(updateProPath))
                {
                    file.remove(updateProPath);
                }

                if(dir.exists(updateResourcePath))
                {
                    clearDirectory(updateResourcePath);
                }

                //开始更新，首先更新pro和数据库，接着更新资源文件
                if (!file.copy(usbDBPath, updateDBPath))
                {
                    emit updateFinish(-3, project);
                    this->getBackUpData();
                    return;
                }

                if (!copyDir(usbResourcePath, updateResourcePath, true))
                {
                    emit updateFinish(-4, project);
                    this->getBackUpData();
                    return;
                }

                if (!file.copy(usbProPath, updateProPath))
                {
                    emit updateFinish(-3, project);
                    this->getBackUpData();
                    return;
                }
                currentVersion = publishTime;
                configClass.setScheduleVersion(currentVersion);
                configClass.setScheduleProName(info.baseName());

                emit updateFinish(0, project);
            }
        }
    }

    m_usbTimer->start(3 * 1000);
}

//卸载U盘,先逐个U盘卸载,如果全部卸载完成,那么完成,如果没有,那么再启动卸载定时器,间隔2秒后继续卸载
void UpdateFile::umountUsb()
{
#ifdef _TTY_POSIX_
    for(int i = 0; i < m_usbPathList.count(); i++)
    {
//        qDebug() << "-------------- umountUsb----------------";
        QString usbPath = m_usbPathList.at(i);
        pid_t child;
        child = fork();
        if (child == 0)
        {
            char mountBuf[128] = {0};
            strcpy(mountBuf, usbPath.toLatin1().data());

            //exec函数，调用shell命令，如果调用成功，不返回任何值，失败返回-1
            execl("/bin/umount", "umount", mountBuf, NULL);

            exit(0);

        }
        int waitStatus;
        waitpid(-1, &waitStatus, NULL);

        if (m_umountCount > UMOUNTMAXCOUNT)
        {
            emit umountUsbState(-1);
            m_usbPathList.removeAt(i);
            i--;
            return;
        }

        QDir dir(usbPath);
        if (dir.exists())
        {
            if (m_umountCount)
                m_umountCount++;
        } else {
            m_umountCount = 0;

            emit umountUsbState(0);
            m_usbPathList.removeAt(i);
            i--;
        }

    }

    if (m_usbPathList.count() > 0)
    {
        m_usbTimer->start(2 * 1000);
    } else {
        m_usbTimer->stop();
    }
#endif
}

QDir dirfrom("/tmp/sdd") ;  //源路径
QDir dirto("/tmp/sdd1");    //目标路径所在位置
int dirlist()              //列出所有文件，并复制
{
    QFile file;
    QFileInfoList list = dirfrom.entryInfoList();
    //std::cout <<"a1"<<std::endl;
    for (int i = 0; i < list.size(); ++i)
    {
        QFileInfo fileInfo = list.at(i);
        if ((fileInfo.fileName() != ".") && (fileInfo.fileName()!=".."))
        {
            if(fileInfo.isDir())    //判断是否为目录
            {
                dirfrom.setPath(dirfrom.path()+"/"+fileInfo.fileName()) ;
                dirto.mkdir(dirto.path()+"/"+fileInfo.fileName());
                dirto.setPath(dirto.path()+"/"+fileInfo.fileName());
                dirlist();    //递归调用
                dirfrom.cdUp();
                dirto.cdUp();
            }
            else
            {
                QString s;
                s = dirfrom.relativeFilePath(fileInfo.absoluteFilePath());    //取得文件相对目标目录的相对路径
                file.copy(fileInfo.absoluteFilePath(),dirto.path()+"/"+s);    //复制代码
            }
        }
    }

    return 0;
}


bool FindFile(const QString & path)
{
    QDir dir(path);
    if (!dir.exists())
    {
        return false;
    }

    dir.setFilter(QDir::Dirs|QDir::Files);//过虑器，包括文件夹及文件
    dir.setSorting(QDir::DirsFirst);      //排序
    QFileInfoList list = dir.entryInfoList();
    int i=0;
    do{

        QFileInfo fileInfo = list.at(i);
        if(fileInfo.fileName()=="." || fileInfo.fileName()=="..")
        {
            i++;
            continue;
        }
        bool bisDir=fileInfo.isDir();

        if(bisDir)//为目录
        {
            //==============================================
            if(fileInfo.fileName()=="PIDS")
            {
                QString strPath = fileInfo.absoluteFilePath() + "/udpate.ini";
            }
            FindFile(fileInfo.filePath());
        }
        else  //为文件
        {
//            nFiles++;
//            std::cout << qPrintable(QString("%1 %2 %3").arg(fileInfo.size(), 10)
//                                    .arg(fileInfo.fileName(),10).arg(fileInfo.path()))<<endl;
        }

        i++;

    }while(i<list.size());

    return true;
}


